/*
  Author:		Damian Esteves
  Project Page:	http://code.google.com/p/snespadplus/
  Based on: 	SNESpad http://code.google.com/p/nespad/  

  
  SNESPadPlus is an Arduino library for interfacing with one or two SNES controllers.
  It is based on the SNESpad library under rights granted by the GPL v3.
  
  Version 0.5:	First release. Arbitrary decimal version number chosen.
  
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 3 of the License, or
  (at your option) any later version.

  This program is distributed without any warranty, even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.  
*/

#include "SNESPadPlus.h"
#include "WProgram.h"

/*
	The SNES controller pinout:
		1: 	+5v (Flat end of connector)
		2: 	Clock
		3: 	Strobe
		4: 	Serial Data
		5: 	N/C
		6: 	N/C
		7: 	GND (Round end of connector)
*/

/*
	Constructor for using 1 controller.
	strobe: strobe pin number
	clock: clock pin number
	data: serial data pin number for controller 1
*/
SNESPadPlus::SNESPadPlus(int strobe, int clock, int data)
  : m_strobe (strobe),
  m_clock (clock),
  m_data (data)
  {
    pinMode(strobe, OUTPUT);
    pinMode(clock,  OUTPUT);
    pinMode(data, INPUT);
  }
/*
	Constructor for using 2 controllers. Reuses the clock and strobe pins.
	Only 1 additional pin is used for the second controller's data pin.
	strobe: strobe pin number
	clock: clock pin number
	data: serial data pin number for controller 1
	data2: serial data pin number for controller 2
*/
SNESPadPlus::SNESPadPlus(int strobe, int clock, int data, int data2)
  : m_strobe (strobe),
  m_clock (clock),
  m_data (data),
  m_data2 (data2)
  {
    pinMode(strobe, OUTPUT);
    pinMode(clock, OUTPUT);
    pinMode(data, INPUT);
	pinMode(data2, INPUT);
  }

/*
	buttons() is used to read from the first controller ONLY.
	Returns a 16-bit integer.
	Each one of the lower 12 bits represents a button/direction on the controller.
	A 0 on a bit means the button is unpressed, a 1 means pressed.
	BIT0	B
	BIT1	Y
	BIT2	SELECT
	BIT3	START
	BIT4	UP
	BIT5	DOWN
	BIT6	LEFT
	BIT7	RIGHT
	BIT8	A
	BIT9	X
	BIT10	L
	BIT11	R
*/  
int SNESPadPlus::buttons(void)
{
  int ret = 0;
  byte i;
  strobe();
  for (i = 0; i < 16; i++) {
    ret |= shiftIn2() << i;
  }
  return ~ret;
}

/*
	buttons() is used to read from both controllers at the same time.
	Returns a 32-bit unsigned long.
	Bits 0-12 represent buttons on Controller 1.
	Bits 16-27
	A 0 on a bit means the button is unpressed, a 1 means pressed.
	Controller 1:
		BIT0	B
		BIT1	Y
		BIT2	SELECT
		BIT3	START
		BIT4	UP
		BIT5	DOWN
		BIT6	LEFT
		BIT7	RIGHT
		BIT8	A
		BIT9	X
		BIT10	L
		BIT11	R
	Controller 2:
		BIT16	B
		BIT17	Y
		BIT18	SELECT
		BIT19	START
		BIT20	UP
		BIT21	DOWN
		BIT22	LEFT
		BIT23	RIGHT
		BIT24	A
		BIT25	X
		BIT26	L
		BIT27	R
*/    
unsigned long SNESPadPlus::buttons2(void)
{
  unsigned long ret = 0;
  byte i;
  strobe();
  for (i = 0; i < 16; i++) {
    ret |= shiftIn2() << i;
  }
  return ~ret;
}

void SNESPadPlus::strobe(void)
{
  digitalWrite(m_strobe,HIGH);
  delayMicroseconds(12);
  digitalWrite(m_strobe,LOW);
}

int SNESPadPlus::shiftIn(void)
{
  int ret = digitalRead(m_data);
  delayMicroseconds(12);
  digitalWrite(m_clock,HIGH);
  delayMicroseconds(12);
  digitalWrite(m_clock,LOW);
  return ret;
}

unsigned long SNESPadPlus::shiftIn2(void)
{
  unsigned long ret = digitalRead(m_data);
  unsigned long temp = digitalRead(m_data2); 
  ret |= temp << 16; //left shift 16 times into 2nd word (bits 16-31)
  delayMicroseconds(12);
  digitalWrite(m_clock,HIGH);
  delayMicroseconds(12);
  digitalWrite(m_clock,LOW);
  return ret;
}
